# ~*~ coding: utf-8 ~*~

from flask import request, views, render_template, jsonify
from flask_login import current_user
from apps.common.utils import fill_date_to_timestamp, timestamp_obj_to_str
from apps.common.mixin import CompatibleWithSelect2Mixin
from apps.common import response
from apps.extensions import db
from apps.perms.mixin import PermissionRequiredMixin, LoginRequiredMixin
from apps.users.models import User
from apps.assets.models import AssetPermission, AssetPermissionRelated, SystemUser, Asset
from ..forms import AuthCreateUpdateForm

__all__ = [
    'AuthListAPI', 'AuthListView', 'AuthCreateView', 'AuthUpdateView', 'AuthDeleteView'
]


class AuthListAPI(CompatibleWithSelect2Mixin, PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'assets-auth-list'

    def get(self):
        create_time = request.args.get('create_time')
        start_time = end_time = None
        if create_time:
            start_time = fill_date_to_timestamp('start', create_time.split('~')[0])
            end_time = fill_date_to_timestamp('end', create_time.split('~')[1])

        filter_conditions = {
            'and': [
                ('create_time', 'gte', start_time),
                ('create_time', 'lte', end_time),
            ],
            'or': [
                ('name', 'like', request.args.get('search')),
            ],
        }

        # 排序
        sort = request.args.get('sort') or 'create_time'
        order = request.args.get('order') or 'desc'
        order_by_list = [(sort, order), ]

        # 分页
        offset = request.args.get('offset') or 0
        limit = request.args.get('limit') or 12

        # Compatible with select2
        if request.values.get('type') == 'select2':
            filter_conditions, order_by_list, offset, limit = self.select2_queryset()

        asset_permissions, count = AssetPermission.get_queryset(
            filter_conditions=filter_conditions,
            order_by_list=order_by_list,
            offset=offset,
            limit=limit
        )

        # 优化查询
        asset_permission_ids = [asset_permission.id for asset_permission in asset_permissions]
        asset_permission_relates = db.session.query(
            AssetPermissionRelated.asset_permission_id,
            db.func.count(db.distinct(AssetPermissionRelated.user_id.label('user_count'))),
            db.func.count(db.distinct(AssetPermissionRelated.asset_id).label('asset_count')),
            db.func.count(db.distinct(AssetPermissionRelated.system_user_id.label('system_user_count'))),
        ). \
            filter(AssetPermissionRelated.asset_permission_id.in_(asset_permission_ids)). \
            group_by(AssetPermissionRelated.asset_permission_id). \
            all()

        # SELECT
        # assets_permission_related.asset_permission_id,
        # count(DISTINCT assets_permission_related.user_id) AS user_count,
        # count(DISTINCT assets_permission_related.asset_id) AS asset_count,
        # count(DISTINCT assets_permission_related.system_user_id) AS  system_user_count
        # FROM
        # assets_permission_related
        # GROUP BY
        # assets_permission_related.asset_permission_id

        asset_permission_related_dict = {}
        # [('4b850d9c29aa442e84d8a7336fd1f774', 1, 1, 1)]
        for asset_permission_related in asset_permission_relates:
            asset_permission_related_dict[asset_permission_related[0]] = {
                'user_count': asset_permission_related[1],
                'asset_count': asset_permission_related[2],
                'system_user_count': asset_permission_related[3],
            }

        results = list()
        for asset_permission in asset_permissions:
            results.append({
                'id': asset_permission.id,
                'name': asset_permission.name,
                'user_count': asset_permission_related_dict.get(asset_permission.id).get(
                    'user_count') if asset_permission_related_dict.get(asset_permission.id) else 0,
                'asset_count': asset_permission_related_dict.get(asset_permission.id).get(
                    'asset_count') if asset_permission_related_dict.get(asset_permission.id) else 0,
                'system_user_count': asset_permission_related_dict.get(asset_permission.id).get(
                    'system_user_count') if asset_permission_related_dict.get(asset_permission.id) else 0,
                'comment': asset_permission.comment,
                'create_by': asset_permission.create_by,
                'create_time': timestamp_obj_to_str(asset_permission.create_time),
            })

        resp = {
            "data": {
                "rows": results,
                "total": count
            }
        }
        return jsonify(resp)


class AuthListView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'assets-auth-list'

    def get(self):
        return render_template('assets/auth_list.html')


class AuthUpdateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'assets-auth-update'

    def get(self, pk):
        instance = db.session.query(AssetPermission).get(pk)
        asset_perm_related = db.session.query(AssetPermissionRelated.asset_id,
                                              AssetPermissionRelated.system_user_id,
                                              AssetPermissionRelated.user_id). \
            filter(AssetPermissionRelated.asset_permission_id == instance.id). \
            all()

        select_assets = select_system_users = select_users = []
        if asset_perm_related:
            select_asset_ids = list(zip(*asset_perm_related))[0]
            select_system_user_ids = list(zip(*asset_perm_related))[1]
            select_user_ids = list(zip(*asset_perm_related))[2]

            select_assets = db.session.query(Asset.id).\
                filter(Asset.id.in_(select_asset_ids)).all()
            select_system_users = db.session.query(SystemUser.id).\
                filter(SystemUser.id.in_(select_system_user_ids)).all()
            select_users = db.session.query(User.id). \
                filter(User.id.in_(select_user_ids)).all()

        try:
            select_assets = list(zip(*select_assets))[0]
        except IndexError:
            select_assets = []

        try:
            select_system_users = list(zip(*select_system_users))[0]
        except IndexError:
            select_system_users = []

        try:
            select_users = list(zip(*select_users))[0]
        except IndexError:
            select_users = []

        content = {
            'select_assets': ','.join(select_assets),
            'select_system_users': ','.join(select_system_users),
            'select_users': ','.join(select_users),
            'id': instance.id,
            'name': instance.name,
            'actions': AssetPermission.value_to_choices(instance.actions),
            'is_active': instance.is_active,
            'comment': instance.comment or ''
        }
        return render_template('assets/auth_update.html', **content)

    def post(self, pk):
        instance = db.session.query(AssetPermission).get(pk)
        form = AuthCreateUpdateForm(request.values)
        if form.validate():
            _clean_data = form.data
            if instance.name != _clean_data.get('name'):
                if db.session.query(AssetPermission).filter_by(name=_clean_data.get('name')).count():
                    return response.params_error({
                        'field': 'name',
                        'message': '主机名称不能重复'
                    })

            user_ids = _clean_data.pop('user_ids').split(',')
            system_user_ids = _clean_data.pop('system_user_ids').split(',')
            asset_ids = _clean_data.pop('asset_ids').split(',')
            actions = _clean_data.pop('actions').split(',')
            _clean_data['actions'] = AssetPermission.choices_to_value(actions)
            asset_permission = instance.update(commit=False, **_clean_data)
            db.session.flush()
            asset_permission.update_related(user_ids, system_user_ids, asset_ids)
            db.session.commit()
            return response.success()
        else:
            return response.params_error(form.get_error())


class AuthCreateView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'assets-auth-create'

    def get(self):
        return render_template('assets/auth_create.html')

    def post(self):
        form = AuthCreateUpdateForm(request.values)
        if form.validate():
            _clean_data = form.data
            if db.session.query(AssetPermission).filter_by(name=_clean_data.get('name')).count():
                return response.params_error({
                    'field': 'name',
                    'message': '权限名称不能重复'
                })

            user_ids = _clean_data.pop('user_ids').split(',')
            system_user_ids = _clean_data.pop('system_user_ids').split(',')
            asset_ids = _clean_data.pop('asset_ids').split(',')
            actions = _clean_data.pop('actions').split(',')
            _clean_data['actions'] = AssetPermission.choices_to_value(actions)
            _clean_data['create_by'] = current_user.name
            asset_permission = AssetPermission.create(commit=False, **_clean_data)
            db.session.flush()
            asset_permission.create_related(user_ids, system_user_ids, asset_ids)
            db.session.commit()
            return response.success()
        else:
            return response.params_error(form.get_error())


class AuthDeleteView(PermissionRequiredMixin, LoginRequiredMixin, views.MethodView):
    permission_required = 'assets-auth-delete'

    def post(self, pk):
        instance = db.session.query(AssetPermission).get(pk)
        db.session.delete(instance)
        instance.delete_related()
        db.session.commit()
        return response.success()

